#ifndef CIRCULAR_ARRAY_H
#define CIRCULAR_ARRAY_H

#include <iostream>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>

#include "locker.h"
using namespace std;

template <typename T>
class circular_array
{
public:
    circular_array(int max_size = 1000){
        if( max_size <= 0 ){
            exit(-1);
        }
        m_capacity = max_size;
        m_array = new T[m_capacity];
        m_size = 0;
        //左闭右开
        m_front = 0;
        m_back = 0;
    }
    ~circular_array(){
        m_mutex.lock();
        if( m_array != NULL ){
            delete [] m_array;
        }
        m_mutex.unlock();
    }
    void clear(){
        m_mutex.lock();
        m_size = 0;
        m_front = -1;
        m_back = -1;
        m_mutex.unlock();
    }
    
    bool full(){
        m_mutex.lock();
        if( m_size >= m_capacity ){
            m_mutex.unlock();
            return true;
        }
        m_mutex.unlock();
        return false;
    }
    bool empty(){
        m_mutex.lock();
        if( m_size == 0 ){
            m_mutex.unlock();
            return true;
        }
        m_mutex.unlock();
        return false;   
    }
    bool front( T& val ){
        m_mutex.lock();
        if( 0 == m_size ){
            m_mutex.unlock();
            return false;
        }
        val = m_array[m_front];
        m_mutex.unlock();
        return true;
    }
    bool back( T& val ){
        m_mutex.lock();
        if( 0 == m_size ){
            m_mutex.unlock();
            return false;
        }
        val = m_array[m_back];
        m_mutex.unlock();
        return true;
    }
    int size(){
        int tmp = 0;
        m_mutex.lock();
        tmp = m_size;
        m_mutex.unlock();
        return tmp; 
    }
    int capacity(){
        int tmp = 0;
        m_mutex.lock();
        tmp = m_capacity;
        m_mutex.unlock();
        return tmp; 
    }
    bool push( const T& item ){
        m_mutex.lock();
        if( m_size >= m_capacity ){
            m_cond.broadcast();
            m_mutex.unlock();
            return false;
        }
        m_array[ m_back ] = item;
        m_back = ( m_back + 1 )%m_capacity;
        m_size++;
        m_cond.broadcast();
        m_mutex.unlock();
        return true;
    }
    bool pop( T& item ){
        m_mutex.lock();
    //多个消费者的时候
        while( m_size <= 0 ){
            /*
            m_cond.wait( m_mutex.get())阻塞，释放锁，等待条件变量满足
            条件变量满足后，如果
            m_cond.wait( m_mutex.get()) 返回 0 
                代表 竞争互斥锁成功(上锁)，处理完后siz还是<=0,其他的继续阻塞
            m_cond.wait(m_mutex.get()) 返回 非0
                代表出错 释放互斥锁 
            */
            if( !m_cond.wait( m_mutex.get() )  ){
                m_mutex.unlock();
                return false;
            }
        }
        item = m_array[ m_front ];
        m_front = ( m_back + 1 )%m_capacity;
        m_size--;
        m_mutex.unlock();
        return true;
    }
    //bool pop( T& item , int timeout);
private:
    locker m_mutex;
    cond m_cond;

    T* m_array;
    int m_size;
    int m_capacity;
    int m_front;
    int m_back;
};

#endif // !CIRCULAR_ARRAY_H